package com.lzyyj.gmis.base.dao.hibernate;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class EnumUserType<E extends Enum<E>> implements UserType {

	private static final Log log = LogFactory.getLog(EnumUserType.class);

	private Class<E> clazz = null;

	private static final int[] SQL_TYPES = {Types.TINYINT, Types.INTEGER, Types.VARCHAR };

	protected EnumUserType(Class<E> enumClass) {
		this.clazz = enumClass;
	}

	@Override
	public int[] sqlTypes() {
		return SQL_TYPES;
	}

	@Override
	public Class<E> returnedClass() {
		return clazz;
	}

	@Override
	public Object assemble(Serializable cached, Object owner)
			throws HibernateException {
		return cached;
	}

	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	@Override
	public Serializable disassemble(Object value) throws HibernateException {
		return (Serializable) value;
	}

	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if (x == y)
			return true;
		if (null == x || null == y)
			return false;
		return x.equals(y);
	}

	@Override
	public int hashCode(Object x) throws HibernateException {
		return x.hashCode();
	}

	@Override
	public Object nullSafeGet(ResultSet resultSet, String[] strings, SharedSessionContractImplementor sharedSessionContractImplementor, Object o) throws HibernateException, SQLException {
		return null;
	}

	@Override
	public void nullSafeSet(PreparedStatement preparedStatement, Object o, int i, SharedSessionContractImplementor sharedSessionContractImplementor) throws HibernateException, SQLException {

	}

	@Override
	public boolean isMutable() {
		return false;
	}

	public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
			throws HibernateException, SQLException {
		E result = null;
		if (!resultSet.wasNull()) {
			String name;
			switch (resultSet.getType()){
			case Types.VARCHAR:
				name = resultSet.getString(names[0]).toUpperCase();
				break;
			default:
				Integer intValue = resultSet.getInt(names[0]);
				if (intValue!=null){
					for (E en:clazz.getEnumConstants()) {  
			            if (intValue.equals(en)) {  
			            	name = en.name();
			            	break;
			            }  
			        } 
				}
				name = resultSet.getString(names[0]).toUpperCase();
				break;
			}
			result = Enum.valueOf(clazz, name);
		}
		return result;
	}

	public void nullSafeSet(PreparedStatement prepareStatement, Object value, int index) throws HibernateException, SQLException {
		
		if (null == value) {
			prepareStatement.setNull(index, Types.VARCHAR);
		} else {
			prepareStatement.setString(index, ((Enum) value).name());
		}
	}

	@Override
	public Object replace(Object original, Object target, Object owner) throws HibernateException {
		// TODO Auto-generated method stub
		return original;
	}

	public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor arg2, Object arg3) throws HibernateException, SQLException {
		E result = null;
		if (!resultSet.wasNull()) {
			String name;
			switch (resultSet.getType()){
				case Types.VARCHAR:
					name = resultSet.getString(names[0]).toUpperCase();
					break;
				default:
					Integer intValue = resultSet.getInt(names[0]);
					if (intValue!=null){
						for (E en:clazz.getEnumConstants()) {
							if (intValue.equals(en)) {
								name = en.name();
								break;
							}
						}
					}
					name = resultSet.getString(names[0]).toUpperCase();
					break;
			}
			result = Enum.valueOf(clazz, name);
		}
		return result;
	}

	public void nullSafeSet(PreparedStatement prepareStatement, Object value, int index, SessionImplementor arg3) throws HibernateException, SQLException {

		if (null == value) {
			prepareStatement.setNull(index, Types.VARCHAR);
		} else {
			prepareStatement.setString(index, ((Enum) value).name());
		}
	}

}